// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_ROOT_META_CACHE_HPP_
#define _XBASE_ROOT_META_CACHE_HPP_

#include <list>

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/deadline_timer.hpp>

#include "protocol.hpp"
#include "sync_handler.hpp"
#include "session_manager.hpp"
#include "async_module_base.hpp"

namespace xbase
{
	class root_meta_cache
		: public async_module_base<io_service_pool::xbase_level, io_service_pool::xbase_level>
	{
	public:
		typedef async_module_base<io_service_pool::xbase_level, io_service_pool::xbase_level> base_type;
		typedef root_meta_cache this_type;
		typedef boost::intrusive_ptr<this_type> ptr_type;

		typedef session_manager::endpoint_type endpoint_type;

		typedef protocol::packet_type<protocol::ROOT_META_REQ>::type request_packet_type;
		typedef protocol::packet_type<protocol::ROOT_META_REQ>::ptr_type request_packet_ptr;
		typedef protocol::packet_type<protocol::ROOT_META_RESP>::type response_packet_type;
		typedef protocol::packet_type<protocol::ROOT_META_RESP>::ptr_type response_packet_ptr;

		typedef protocol::tablet_info tablet_info;
		typedef protocol::server_address server_address;

		typedef boost::system::error_code error_code;
		typedef boost::function<void(const error_code&)> handler_type;

		typedef std::list<handler_type> handler_list;

		typedef basic_sync_handler<> sync_handler_type;

	public:
		root_meta_cache(io_service_pool &pool,
			const endpoint_type &endpoint,
			session_manager &session_manager_ref)
			: base_type(pool),
			m_root_meta_got(false),
			m_master_server_endpoint(endpoint),
			m_session_manager(session_manager_ref),
			m_options(pool.options()),
			m_retry_times(0)
		{
		}

		void async_get_root_meta(handler_type handler, bool hard = false)
		{
			this->get_lower_level_service().dispatch(
				boost::bind(
				&this_type::on_async_get_root_meta, this_ptr(), handler, hard
				)
				);
		}

		error_code get_root_meta(tablet_info &ti, server_address &sa)
		{
			async_get_root_meta(m_sync_handler.make_handler());
			m_sync_handler.wait();

			ti = m_root_tablet_info;
			sa = m_root_server_addr;
			error_code ec = m_sync_handler.get_error_code();

			return ec;
		}

		const tablet_info& get_root_tablet_info()
		{
			return m_root_tablet_info;
		}

		const server_address& get_root_server_address()
		{
			return m_root_server_addr;
		}

	private:
		void on_async_get_root_meta(handler_type handler, bool hard);

		void on_get_root_meta_response(protocol::packet_ptr pkt_ptr, const error_code &ec);

		void on_retry();

		void on_fail(const error_code &ec);

		void on_error(const error_code &ec);

	protected:
		// 缓冲模块不需要ptr_type来持有
		this_type *this_ptr() {
			return this;
		}

	private:
		bool m_root_meta_got;
		endpoint_type m_master_server_endpoint;
		tablet_info m_root_tablet_info;
		server_address m_root_server_addr;
		session_manager &m_session_manager;

		handler_list m_handler_list;

		boost::shared_ptr<boost::asio::deadline_timer> m_timer;
		const client_options &m_options;
		unsigned m_retry_times;

		sync_handler_type m_sync_handler;
	};
	
	typedef root_meta_cache::ptr_type root_meta_cache_ptr;
}

#endif

